package com.market.domain;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.faces.context.FacesContext;
import javax.persistence.Transient;

/**
 * Base class for domain objects. Child objects should implement toString(),
 * equals(), hashCode() and equalsId().
 * 
 * @author Tong Huang
 */
public abstract class BaseObject implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6673474507520347464L;

	private static final DecimalFormat df = new DecimalFormat("#.00");
	
	
	public abstract void setId(Long id);
	public abstract Long getId();
	

	protected String formatDoubleToString(Double d) {
		if (d >= 1D || d <= -1D) {
			return df.format(d);
		} else {
			return "0" + df.format(d);
		}
	}

	protected String getMessage(String key, Locale locale) {
		java.util.ResourceBundle resBundle = ResourceBundle.getBundle(
				"com.market.messages", locale);
		return resBundle.getString(key);
	}

	protected String getMessage(String key) {
		Locale locale = FacesContext.getCurrentInstance().getViewRoot()
				.getLocale();
		java.util.ResourceBundle resBundle = ResourceBundle.getBundle(
				"com.market.messages", locale);
		return resBundle.getString(key);
	}

	protected Locale getLocale() {
		return FacesContext.getCurrentInstance().getViewRoot().getLocale();
	}

	/**
	 * Check if the String is empty, empty means null,all spaces' string, empty
	 * string
	 * 
	 * @param s
	 * @return
	 */
	protected boolean isEmpty(String s) {
		if (s == null || s.trim().isEmpty()) {
			return true;
		}
		return false;
	}

	/**
	 * This method get localize String of specific property, There is a rule for
	 * each locale: For English, if English property is not empty, return
	 * English property, or French property will be returned, Chinese property
	 * will be return if both of them are empty. For French,
	 * French->English->Chinese For Chinese, Chinese->English->French
	 * 
	 * @param propertyName
	 * @param locale
	 * @return
	 */
	protected String getLabel(Object obj, String propertyName, Locale locale) {
		String englisthMethodName = "get" + propertyName;
		String chineseMethodName = "getChinese" + propertyName;
		String frenchMethodName = "getFrench" + propertyName;
		try {
			Method englishMethod = obj.getClass().getMethod(englisthMethodName,
					null);
			Method chineseMethod = obj.getClass().getMethod(chineseMethodName,
					null);
			Method frenchMethod = obj.getClass().getMethod(frenchMethodName,
					null);
			String englishLabel = (String) englishMethod.invoke(this, null);
			String chineseLabel = (String) chineseMethod.invoke(this, null);
			String frenchLabel = (String) frenchMethod.invoke(this, null);

			if (locale.getLanguage().equalsIgnoreCase("en")) {
				if (!this.isEmpty(englishLabel)) {
					return englishLabel;
				}
				if (!this.isEmpty(frenchLabel)) {
					return this.getMessage("french", locale) + ":"
							+ frenchLabel;
				}
				if (!this.isEmpty(chineseLabel)) {
					return this.getMessage("chinese", locale) + ":"
							+ chineseLabel;
				}
			}

			if (locale.getLanguage().equalsIgnoreCase("fr")) {
				if (!this.isEmpty(frenchLabel)) {
					return frenchLabel;
				}
				if (!this.isEmpty(englishLabel)) {
					return this.getMessage("english", locale) + ":"
							+ englishLabel;
				}
				if (!this.isEmpty(chineseLabel)) {
					return this.getMessage("chinese", locale) + ":"
							+ chineseLabel;
				}
			}

			if (locale.getLanguage().equalsIgnoreCase("zh")) {
				if (!this.isEmpty(chineseLabel)) {
					return chineseLabel;
				}
				if (!this.isEmpty(englishLabel)) {
					return this.getMessage("english", locale) + ":"
							+ englishLabel;
				}
				if (!this.isEmpty(frenchLabel)) {
					return this.getMessage("french", locale) + ":"
							+ frenchLabel;
				}
			}
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * This method get localize String of specific property, There is a rule for
	 * each locale: For English, if English property is not empty, return
	 * English property, or French property will be returned, Chinese property
	 * will be return if both of them are empty. For French,
	 * French->English->Chinese For Chinese, Chinese->English->French
	 * 
	 * @param propertyName
	 * @param locale
	 * @return
	 */
	protected String getLabel(String propertyName, Locale locale) {
		return this.getLabel(this, propertyName, locale);
		// String englisthMethodName = "get" + propertyName;
		// String chineseMethodName = "getChinese" + propertyName;
		// String frenchMethodName = "getFrench" + propertyName;
		// try {
		// Method englishMethod = this.getClass().getMethod(
		// englisthMethodName, null);
		// Method chineseMethod = this.getClass().getMethod(chineseMethodName,
		// null);
		// Method frenchMethod = this.getClass().getMethod(frenchMethodName,
		// null);
		// String englishLabel = (String) englishMethod.invoke(this, null);
		// String chineseLabel = (String) chineseMethod.invoke(this, null);
		// String frenchLabel = (String) frenchMethod.invoke(this, null);
		//
		// if (locale.getLanguage().equalsIgnoreCase("en")) {
		// if (!this.isEmpty(englishLabel)) {
		// return englishLabel;
		// }
		// if (!this.isEmpty(frenchLabel)) {
		// return this.getMessage("french", locale) + ":"
		// + frenchLabel;
		// }
		// return this.getMessage("chinese", locale) + ":" + chineseLabel;
		// }
		//
		// if (locale.getLanguage().equalsIgnoreCase("fr")) {
		// if (!this.isEmpty(frenchLabel)) {
		// return frenchLabel;
		// }
		// if (!this.isEmpty(englishLabel)) {
		// return this.getMessage("english", locale) + ":" + englishLabel;
		// }
		// return this.getMessage("chinese", locale) + ":" + chineseLabel;
		// }
		//
		// if (locale.getLanguage().equalsIgnoreCase("zh")) {
		// if (!this.isEmpty(chineseLabel)) {
		// return chineseLabel;
		// }
		// if (!this.isEmpty(englishLabel)) {
		// return this.getMessage("english", locale) +":" + englishLabel;
		// }
		// return this.getMessage("french", locale) + ":" + frenchLabel;
		// }
		// } catch (SecurityException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// } catch (NoSuchMethodException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// } catch (IllegalArgumentException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// } catch (IllegalAccessException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// } catch (InvocationTargetException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		// return null;
	}

	/**
	 * This is a flag show this object is newly created object that hasn't been
	 * saved to database Or is an object from database, Default is false;
	 */
	private boolean isNew = false;

	public boolean getIsNew() {
		return isNew;
	}

	public void setIsNew(boolean isNew) {
		this.isNew = isNew;
	}

	/**
	 * This property use by view to save if this item is selected by user;
	 */
	@Transient
	private boolean selected;

	public boolean getSelected() {
		return selected;
	}

	public void setSelected(boolean selected) {
		this.selected = selected;
	}

	/**
	 * This is a flag show if the associated objects is loaded. For example,
	 * OrderDetail is associated objects of Order, this flag show whether those
	 * OrderDetails of Order have been loaded;
	 * 
	 */
	@Transient
	private Boolean isAssociatedLoaded = Boolean.FALSE;

	public Boolean getIsAssociatedLoaded() {
		return isAssociatedLoaded;
	}

	public void setIsAssociatedLoaded(Boolean isAssociatedLoaded) {
		this.isAssociatedLoaded = isAssociatedLoaded;
	}

	/**
	 * Returns a multi-line String with key=value pairs.
	 * 
	 * @return a String representation of the object this class.
	 */
	public abstract String toString();

	/**
	 * Compares object equality. When using Hibernate, the primary key should
	 * not be a part of this comparison.
	 * 
	 * @param o
	 *            object to compare to
	 * @return true/false based on equality tests
	 */
	public abstract boolean equals(Object o);

	/**
	 * Compares primary key of two object
	 * 
	 * @param o
	 * @return
	 */
	public abstract boolean equalsId(Object o);

	/**
	 * When you override equals, you should override hashCode. See "Why are
	 * equals() and hashCode() importation" for more information:
	 * http://www.hibernate.org/109.html
	 * 
	 * @return hashCode
	 */
	public abstract int hashCode();
}
